﻿using System;
using Microsoft.VisualStudio.TestTools.WebTesting;

namespace InfoPathExtractionRules
{
    static class IPExtractionUtil
    {
        public const string VarName = "var g_objCurrentFormData = [";
        public const string CanaryStart = "_InfoPath_CanaryValue";
        public const string EventLogFormPostbackParameterName = "__EventLog";

        public const string DefaultFormServerPath = "/_layouts/FormServer.aspx";
        public const string PartialPostbackPath = "/_layouts/Postback.FormServer.aspx";

        /// <summary>
        /// Finds the javascript declaration for g_ObjCurrentFormData
        /// </summary>
        /// <param name="body">String body from a server HTTP response</param>
        /// <returns>RHS of the assignment to g_ObjCurrentFormData</returns>
        public static string getg_ObjCurrentFormData(string body)
        {
            // Find where the g_objCurrentFormData is defined in javascript
            int varStart = body.IndexOf(VarName);
            // We're going to extract the substring after the = [ of the javascript var
            varStart += VarName.Length;
            int varEnd = body.IndexOf("];", varStart);
            int varLength = varEnd - varStart; // Not adding 1 to skip the close bracket

            string var = body.Substring(varStart, varLength);
            return var;
        }

        /// <summary>
        /// Parses a javascript array declaration and returns an item from it
        /// </summary>
        /// <param name="var">The string that would be on the RHS of a javascript array declaration
        /// and between brackets</param>
        /// <param name="itemIndex">Index of the item in the array to return</param>
        /// <returns>Item from "var" array at specified index</returns>
        public static string extractItemFromJavascriptArray(string var, int itemIndexIn)
        {
            int startIndex = 0;
            int itemIndex = 0;
            int nesting = 0;
            char c;
            // Parse the items in the array
            // The items in the array are separated by commas,
            // but the array can contain other arrays which can contain commas
            for (int i = 0; i < var.Length; i++)
            {
                c = var[i];

                // Take into account arrays within this array
                if (c == '[')
                {
                    nesting++;
                }
                else if (c == ']')
                {
                    nesting--;
                }

                // If we are not in an internal array and
                // we reached a comma or the end of the string,
                // then we parsed an item
                if (nesting == 0 && (c == ',' || i == var.Length - 1))
                {
                    if (itemIndex == itemIndexIn)
                    {
                        string item = getSubString(var, startIndex, i);
                        return item.Trim(',');
                    }

                    startIndex = i + 1;
                    itemIndex++;
                }
            }

            return null;
        }

        /// <summary>
        /// Gets a substring using a start and end index range
        /// </summary>
        /// <param name="str">String to extract the substring from</param>
        /// <param name="startIndex">First character in "str" where the substring begins</param>
        /// <param name="endIndex">Last character in "str" where the substring ends</param>
        /// <returns>Substring from "str" from startIndex to endIndex</returns>
        public static string getSubString(string str, int startIndex, int endIndex)
        {
            int length = endIndex - startIndex + 1;
            return str.Substring(startIndex, length);
        }


        public static bool IsInvocation(WebTestRequest req, string InvocationPath)
        {
            // Check if the request is using the GET transport method
            // and that the url is for an invocation
            return (req.Method == "GET") && (req.Url.Contains(InvocationPath));
        }

        public static bool IsPartialPostback(WebTestRequest req)
        {
            // Check if the request is using the POST transport method
            // and that the url is for an postback
            return (req.Method == "POST") && (req.Url.Contains(PartialPostbackPath));
        }

        public static bool IsFullPagePostback(WebTestRequest req, string InvocationPath)
        {
            // Check if the request is using the POST transport method
            // and that the url is for an invocation
            return (req.Method == "POST") && (req.Url.Contains(InvocationPath));
        }

        public static string SubstituteCurrentFormData(string body, WebTestContext context)
        {
            EventLog log = new EventLog(body);
            CurrentFormData data = (CurrentFormData)context[CurrentFormData.ContextParameterName];

            log.eventLogInfo.Canary = data.Canary;
            log.eventLogInfo.EditingSessionId = data.EditingSessionId;
            log.eventLogInfo.SolutionId = data.SolutionId;

            return log.ToString();
        }
    }
}
